package com.blockmeta.bbs.immodule.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.FrameLayout;

import com.blockmeta.bbs.baselibrary.utils.DimentionsUtil;
import com.blockmeta.bbs.immodule.R;

/**
 * @author AirThor
 * @date 2020/3/4.
 */
public class IMBubbleImageView extends FrameLayout {
    private RectF mSaveRect = new RectF();
    private RectF mPathRect = new RectF();
    private Paint mSavePaint = new Paint();
    private Paint mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Path mBubblePath = new Path();

    private float mCornerRadus = DimentionsUtil.dp2px(4f);
    private float mTriangleHeight = DimentionsUtil.dp2px(8f);
    private float mTriangleBottomWidth = DimentionsUtil.dp2px(8f);
    private float mTriangleTopMargin = DimentionsUtil.dp2px(15f);
    private TriangleSide mTriangleSide;

    public IMBubbleImageView(Context context) {
        this(context, null);
    }

    public IMBubbleImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IMBubbleImageView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IMBubbleImageView);
        int location = array.getInt(R.styleable.IMBubbleImageView_bubbleSide, 0);
        mTriangleSide = TriangleSide.mapIntToValue(location);
        array.recycle();

        init(context);
    }
    private void init(Context context){
        mSavePaint.setXfermode(null);
        mPathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mPathPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        mSaveRect.set(0f,0f,canvas.getWidth(),canvas.getHeight());
        int saveNum = canvas.saveLayer(mSaveRect,mSavePaint,Canvas.ALL_SAVE_FLAG);
        super.dispatchDraw(canvas);
        if (mTriangleSide==TriangleSide.LEFT){
            drawLeftBubble(canvas);
        }else {
            drawRightBubble(canvas);
        }
        canvas.restoreToCount(saveNum);
    }

    private void drawRightBubble(Canvas canvas) {
        drawBottomLeft(canvas);
        drawTopLeft(canvas);
        mBubblePath.reset();
        mBubblePath.moveTo(getMeasuredWidth()-mTriangleHeight-mCornerRadus,0);
        mPathRect.set(getMeasuredWidth()-mTriangleHeight-mCornerRadus*2f,0,getMeasuredWidth()-mTriangleHeight,mCornerRadus*2f);
        mBubblePath.addArc(mPathRect,-90,90);
        mBubblePath.lineTo(getMeasuredWidth()-mTriangleHeight,mTriangleTopMargin);
        mBubblePath.lineTo(getMeasuredWidth(),mTriangleTopMargin+mTriangleBottomWidth/2f);
        mBubblePath.lineTo(getMeasuredWidth()-mTriangleHeight,mTriangleTopMargin+mTriangleBottomWidth);
        mBubblePath.lineTo(getMeasuredWidth()-mTriangleHeight,getMeasuredHeight()-mCornerRadus);
        mPathRect.set(getMeasuredWidth()-mTriangleHeight-mCornerRadus*2f,getMeasuredHeight()-mCornerRadus*2f,getMeasuredWidth()-mTriangleHeight,getMeasuredHeight());
        mBubblePath.addArc(mPathRect,0,90);
        mBubblePath.lineTo(getMeasuredWidth(),getMeasuredHeight());
        mBubblePath.lineTo(getMeasuredWidth(),0f);
        mBubblePath.lineTo(getMeasuredWidth()-mTriangleHeight-mCornerRadus,0);
        canvas.drawPath(mBubblePath,mPathPaint);
    }

    private void drawLeftBubble(Canvas canvas) {
        drawBottomRight(canvas);
        drawTopRight(canvas);
        mBubblePath.reset();
        mBubblePath.moveTo(mTriangleHeight+mCornerRadus,0);
        mPathRect.set(mTriangleHeight,0f,mTriangleHeight+mCornerRadus*2f,mCornerRadus*2f);
        mBubblePath.addArc(mPathRect,-90,-90);
        mBubblePath.lineTo(mTriangleHeight,mTriangleTopMargin);
        mBubblePath.lineTo(0f,mTriangleTopMargin+mTriangleBottomWidth/2f);
        mBubblePath.lineTo(mTriangleHeight,mTriangleTopMargin+mTriangleBottomWidth);
        mBubblePath.lineTo(mTriangleHeight,getMeasuredHeight()-mCornerRadus);
        mPathRect.set(mTriangleHeight,getMeasuredHeight()-mCornerRadus*2f,mTriangleHeight+mCornerRadus*2f,getMeasuredHeight());
        mBubblePath.addArc(mPathRect,180,-90);
        mBubblePath.lineTo(0,getMeasuredHeight());
        mBubblePath.lineTo(0,0);
        mBubblePath.lineTo(mTriangleHeight+mCornerRadus,0);
        canvas.drawPath(mBubblePath,mPathPaint);
    }

    private void drawTopLeft(Canvas canvas) {
        if (mCornerRadus > 0) {
            mBubblePath.reset();
            mBubblePath.moveTo(0, mCornerRadus);
            mBubblePath.lineTo(0, 0);
            mBubblePath.lineTo(mCornerRadus, 0);
            mBubblePath.arcTo(new RectF(0, 0, mCornerRadus * 2, mCornerRadus * 2),
                    -90, -90);
            mBubblePath.close();
            canvas.drawPath(mBubblePath, mPathPaint);
        }
    }

    private void drawTopRight(Canvas canvas) {
        if (mCornerRadus > 0) {
            int width = getWidth();
            mBubblePath.reset();
            mBubblePath.moveTo(width - mCornerRadus, 0);
            mBubblePath.lineTo(width, 0);
            mBubblePath.lineTo(width, mCornerRadus);
            mBubblePath.arcTo(new RectF(width - 2 * mCornerRadus, 0, width,
                    mCornerRadus * 2), 0, -90);
            mBubblePath.close();
            canvas.drawPath(mBubblePath, mPathPaint);
        }
    }

    private void drawBottomLeft(Canvas canvas) {
        if (mCornerRadus > 0) {
            int height = getHeight();
            mBubblePath.reset();
            mBubblePath.moveTo(0, height - mCornerRadus);
            mBubblePath.lineTo(0, height);
            mBubblePath.lineTo(mCornerRadus, height);
            mBubblePath.arcTo(new RectF(0, height - 2 * mCornerRadus,
                    mCornerRadus * 2, height), 90, 90);
            mBubblePath.close();
            canvas.drawPath(mBubblePath, mPathPaint);
        }
    }

    private void drawBottomRight(Canvas canvas) {
        if (mCornerRadus > 0) {
            int height = getHeight();
            int width = getWidth();
            mBubblePath.reset();
            mBubblePath.moveTo(width - mCornerRadus, height);
            mBubblePath.lineTo(width, height);
            mBubblePath.lineTo(width, height - mCornerRadus);
            mBubblePath.arcTo(new RectF(width - 2 * mCornerRadus, height - 2
                    * mCornerRadus, width, height), 0, 90);
            mBubblePath.close();
            canvas.drawPath(mBubblePath, mPathPaint);
        }
    }

    public enum TriangleSide{
        LEFT(0x00),
        RIGHT(0x01);

        private int mValue;

        TriangleSide(int value){
            this.mValue = value;
        }

        public static TriangleSide mapIntToValue(int stateInt) {
            for (TriangleSide value : TriangleSide.values()) {
                if (stateInt == value.getIntValue()) {
                    return value;
                }
            }
            return getDefault();
        }

        public static TriangleSide getDefault(){
            return LEFT;
        }

        public int getIntValue() {
            return mValue;
        }
    }

}
